﻿/*
 * @author: wizardc
 */

using UnityEditor;
using UnityEngine;

namespace DouEditor.Extend
{
    /// <summary>
    /// 在 Editor 非运行模式下简单的播放指定骨骼动画
    /// 非运行模式下调用 Play 等方法播放动画无效
    /// </summary>
    [ExecuteInEditMode]
    public class EditorAnimator : MonoBehaviour
    {
        /// <summary>
        /// 默认播放的动画状态名称
        /// </summary>
        public string defaultStateName = "";

        private Animator _animator;

        private bool _bakeComplete = false;

        private float _fps;
        private float _len;
        private int _frames;
        private float _frameDelta;

        private bool _playing = false;

        private void Start()
        {
            _animator = GetComponent<Animator>();
            if (_animator == null)
            {
                Debug.LogError("缺少\"Animator\"组件！");
                return;
            }

            Play(defaultStateName);
        }

        private void Bake(string stateName)
        {
            _bakeComplete = false;

            AnimationClip targetClip = null;
            var clips = _animator.runtimeAnimatorController.animationClips;
            foreach (var clip in clips)
            {
                if (clip.name == stateName)
                {
                    targetClip = clip;
                    break;
                }
            }

            if (targetClip == null)
            {
                Debug.LogError($"没有名为\"{stateName}\"的剪辑！");
                return;
            }

            _animator.Rebind();
            _animator.StopPlayback(); // 关闭回放

            // 录像
            _fps = targetClip.frameRate;
            _len = targetClip.length;
            _frames = Mathf.CeilToInt(_fps * _len);
            _frameDelta = 1f / _fps;
            _animator.StartRecording(_frames);
            _animator.Play(stateName);
            for (int i = 0; i < _frames; i++)
            {
                _animator.Update(_frameDelta);
            }

            _animator.StartPlayback(); // 开始回放记录的动画

            _bakeComplete = true;
        }

        public void Play(string stateName)
        {
            Bake(stateName);
            _playing = true;

            EditorApplication.update -= EditorUpdate;
            EditorApplication.update += EditorUpdate;
        }

        public void Stop()
        {
            _playing = false;

            _animator.playbackTime = 0;
            _animator.Update(0);

            EditorApplication.update -= EditorUpdate;
        }

        private void EditorUpdate()
        {
            if (!_bakeComplete || !_playing)
            {
                return;
            }

            _animator.Update(Time.deltaTime);
        }

        private void OnDestroy()
        {
            EditorApplication.update -= EditorUpdate;
        }
    }
}
